package com.ruoyi.web.money.controller;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.domain.MoneyFund;
import com.ruoyi.system.domain.vo.MoneyFundModel;
import com.ruoyi.web.money.ReadListener;
import com.ruoyi.web.money.common.CacheKey;
import com.ruoyi.web.money.model.ExcelModel;
import com.ruoyi.web.money.service.IMoneyFundService;
import com.ruoyi.web.money.service.IMoneyFundTemperatureService;

/**
 * 基金/股票管理Controller
 *
 * @author ruoyi
 * @date 2021-03-14
 */
@RestController
@RequestMapping("/money/fund")
public class MoneyFundController extends BaseController implements CacheKey {

    @Autowired
    private IMoneyFundService moneyFundService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    IMoneyFundTemperatureService iMoneyFundTemperatureService;

    /**
     * 查询基金/股票管理列表
     */
    @PreAuthorize("@ss.hasPermi('money:fund:list')")
    @GetMapping("/list")
    public TableDataInfo list(MoneyFund moneyFund) {
        startPage();
        List<MoneyFund> list = moneyFundService.selectMoneyFundList(moneyFund);
        return getDataTable(list);
    }


    /**
     * 查询基金/股票管理列表
     */
    @PreAuthorize("@ss.hasPermi('money:fund:list')")
    @PostMapping("/upload")
    public AjaxResult uploadFile(MultipartFile file, @RequestParam Long fundId) throws Exception {
        EasyExcel.read(file.getInputStream(), ExcelModel.class, new ReadListener(redisTemplate, iMoneyFundTemperatureService, fundId))
                .sheet()
                .doRead();
        Boolean success = redisTemplate.opsForValue().setIfAbsent(cacheKey(FUND_LIST_KEY, today(), fundId), "success", 1, TimeUnit.DAYS);
        if (Optional.ofNullable(success).orElse(false)) {
            return AjaxResult.success();
        }
        return AjaxResult.error("数据不完整，无法入库");
    }

    /**
     * 导出基金/股票管理列表
     */
    @PreAuthorize("@ss.hasPermi('money:fund:export')")
    @Log(title = "基金/股票管理", businessType = BusinessType.EXPORT)
    @GetMapping("/export")
    public AjaxResult export(MoneyFund moneyFund) {
        List<MoneyFund> list = moneyFundService.selectMoneyFundList(moneyFund);
        ExcelUtil<MoneyFund> util = new ExcelUtil<MoneyFund>(MoneyFund.class);
        return util.exportExcel(list, "fund");
    }

    /**
     * 获取基金/股票管理详细信息
     */
    @PreAuthorize("@ss.hasPermi('money:fund:query')")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id) {
        return AjaxResult.success(moneyFundService.selectMoneyFundById(id));
    }

    /**
     * 查询基金/股票管理报表
     */
    @PreAuthorize("@ss.hasPermi('money:fund:list')")
    @GetMapping("/time/{id}")
    public AjaxResult listTime(@PathVariable("id") Long id) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        startPage();
        LocalDateTime tenYear = LocalDateTime.now().minus(10, ChronoUnit.YEARS);

        String format = formatter.format(tenYear);
        List<MoneyFundModel> tenYearData = moneyFundService.findTime(id, format);
        if (CollectionUtils.isEmpty(tenYearData)) {
            return AjaxResult.error("no data");
        } else {
            LocalDateTime fiveYear = LocalDateTime.now().minus(5, ChronoUnit.YEARS);
            LocalDateTime thirdYear = LocalDateTime.now().minus(3, ChronoUnit.YEARS);
            LocalDateTime oneYear = LocalDateTime.now().minus(1, ChronoUnit.YEARS);

            List<MoneyFundModel> fiveYearData = buildList(filterModel(fiveYear, tenYearData));
            compute(MoneyFundModel::getPb, MoneyFundModel::setPbValue, null, fiveYearData);
            compute(MoneyFundModel::getPe, MoneyFundModel::setPeValue, MoneyFundModel::getPb, fiveYearData);

            List<MoneyFundModel> thirdYearData = buildList(filterModel(thirdYear, tenYearData));
            compute(MoneyFundModel::getPb, MoneyFundModel::setPbValue, null, thirdYearData);
            compute(MoneyFundModel::getPe, MoneyFundModel::setPeValue, MoneyFundModel::getPb, thirdYearData);

            List<MoneyFundModel> oneYearData = buildList(filterModel(oneYear, tenYearData));
            compute(MoneyFundModel::getPb, MoneyFundModel::setPbValue, null, oneYearData);
            compute(MoneyFundModel::getPe, MoneyFundModel::setPeValue, MoneyFundModel::getPb, oneYearData);

            compute(MoneyFundModel::getPb, MoneyFundModel::setPbValue, null, tenYearData);
            compute(MoneyFundModel::getPe, MoneyFundModel::setPeValue, MoneyFundModel::getPb, tenYearData);
            AjaxResult success = AjaxResult.success();
            tenYearData.sort(Comparator.comparing(MoneyFundModel::getTime));
            fiveYearData.sort(Comparator.comparing(MoneyFundModel::getTime));
            thirdYearData.sort(Comparator.comparing(MoneyFundModel::getTime));
            oneYearData.sort(Comparator.comparing(MoneyFundModel::getTime));
            success.put("ten", tenYearData);
            success.put("five", fiveYearData);
            success.put("third", thirdYearData);
            success.put("one", oneYearData);
            return success;
        }
    }

    private List<MoneyFundModel> buildList(List<MoneyFundModel> data) {
        if (CollectionUtils.isEmpty(data)) {
            return Collections.emptyList();
        }
        return JSONArray.parseArray(JSONObject.toJSONString(data)).toJavaList(MoneyFundModel.class);
    }

    private List<MoneyFundModel> filterModel(LocalDateTime selectTime, List<MoneyFundModel> data) {
        Predicate<MoneyFundModel> filterDate = time -> selectTime.toLocalDate()
                .isBefore(time.getTime().toLocalDate());
        return data.stream().filter(filterDate).collect(Collectors.toList());
    }

    private void compute(Function<MoneyFundModel, Double> mapTemp,
                         BiConsumer<MoneyFundModel, Double> consumerValue,
                         Function<MoneyFundModel, Double> mapOther,
                         List<MoneyFundModel> data) {
        // 排序
        data.sort(Comparator.comparing(mapTemp));
        for (int i = 0; i < data.size(); i++) {
            int index = i;
            MoneyFundModel model = data.get(i);
            while (index != 0 && Optional.of(model).map(mapTemp).orElse(0d)
                    .equals(Optional.of(data.get(index - 1)).map(mapTemp).orElse(0d))) {
                index--;
            }
            Double value = ((double) index / (data.size() - 1)) * 100;
            consumerValue.accept(model, value);
            if (mapOther != null && mapTemp.apply(model) > 0 && mapOther.apply(model) > 0) {
                model.setValue((model.getPbValue() + model.getPeValue()) / 2);
            }
        }


    }

    /**
     * 新增基金/股票管理
     */
    @PreAuthorize("@ss.hasPermi('money:fund:add')")
    @Log(title = "基金/股票管理", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody MoneyFund moneyFund) {
        return toAjax(moneyFundService.insertMoneyFund(moneyFund));
    }

    /**
     * 修改基金/股票管理
     */
    @PreAuthorize("@ss.hasPermi('money:fund:edit')")
    @Log(title = "基金/股票管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody MoneyFund moneyFund) {
        return toAjax(moneyFundService.updateMoneyFund(moneyFund));
    }

    /**
     * 删除基金/股票管理
     */
    @PreAuthorize("@ss.hasPermi('money:fund:remove')")
    @Log(title = "基金/股票管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids) {
        return toAjax(moneyFundService.deleteMoneyFundByIds(ids));
    }
}
